package ogmios.components.archivers;
import java.util.*;
import java.io.*;
import javax.swing.*;
import javax.swing.tree.*;
import java.util.zip.*;
import java.util.regex.*;
import static ogmios.components.FileTree.FileNode;
import ogmios.core.*;
/**
 * An archiver that creates .zip files
 */
public class ZipArchiver implements Archiver
{
 protected volatile boolean stop = false;
 protected volatile boolean running = false;
 public void archive(File outputFile, TreeModel files, Map<String, Object> properties) throws Throwable
 {
   running=true;
   try
   {
    ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(outputFile));
    addFilesToZipOutputStream(zip, files);
    zip.flush();
    zip.close();

   }
   catch(Throwable ex)
   {
     throw ex;
   }
   finally
   {
    stop=false;
    running=false;
   }
 }

 protected void checkToHalt() throws Throwable
 {
   if (stop)
    throw new Exception("Stop flag set to true");
 }

 public void addFilesToZipOutputStream(ZipOutputStream zip, TreeModel files) throws Throwable
 {
  byte[] buffer = new byte[10240];
   for (Enumeration children = ((TreeNode)files.getRoot()).children(); children.hasMoreElements();)
   {
    checkToHalt();
    FileNode fileNode = (FileNode) children.nextElement();
    if (fileNode.nodeType == FileNode.FILE)
    {
      File zipFile = new File(fileNode.path + File.separator + fileNode.name);
      ZipEntry zipEntry = new ZipEntry(fileNode.name);
      zipEntry.setTime(zipFile.lastModified());
      zip.putNextEntry(zipEntry);
      FileInputStream in = new FileInputStream(zipFile);
      int n;
      while ((n = in.read(buffer, 0, buffer.length)) > 0)
      {
        zip.write(buffer, 0, n);
      }
      in.close();
    }
    else
    {
      if (fileNode.getChildCount() != 0)
      {
        Stack<Enumeration> nursery = new Stack<Enumeration>();
        nursery.push(fileNode.children());
        FileNode subJarn;
        int pathLength = fileNode.path.length() + 1;
        Pattern fileSeparators = Pattern.compile("\\\\");
        do
        {
         for (Enumeration subchildren = nursery.pop(); subchildren.hasMoreElements();)
         {
          checkToHalt();
          subJarn = (FileNode)subchildren.nextElement();
          if (subJarn.nodeType == FileNode.FILE)
          {
            File subFileNode = new File(subJarn.path + File.separator + subJarn.name);
            ZipEntry zipEntry = new ZipEntry(fileSeparators.matcher(subJarn.path.substring(pathLength) + File.separator + subJarn.name).replaceAll("/"));
           // ZipEntry zipEntry = new ZipEntry( (subJarn.path.substring(pathLength) + File.separator + subJarn.name).replaceAll("\\\\", "/"));
            zipEntry.setTime(subFileNode.lastModified());
            zip.putNextEntry(zipEntry);
            FileInputStream in = new FileInputStream(subFileNode);
            int n;
            while ((n = in.read(buffer, 0, buffer.length)) > 0)
            {
              zip.write(buffer, 0, n);
            }
            in.close();
           }
           else
           {
             nursery.push(subJarn.children());
           }
          }
        checkToHalt(); 
      }while(!nursery.isEmpty());
    }          
   }
  }
 }

 public void stop()
 {
   if (isRunning())
    stop=true;
 }

 public boolean isRunning()
 {
  return running;
 }

 public String getName()
 {
  return "Zip";
 }

 public Map<String, ArchiveProperties> properties()
 {
  return Collections.<String, ArchiveProperties>emptyMap();
 }


}
